// Known UUID names sourced from:
// - https://github.com/thegecko/webbluetooth/blob/master/src/uuid.ts                           @ 6f1836535eb32a4add509c6dc8e4d311ae97f015
// - https://github.com/WebBluetoothCG/registries/blob/master/gatt_assigned_services.txt        @ b2b66ec139495c2b0b242d22d973dac87d75463c
// - https://github.com/WebBluetoothCG/registries/blob/master/gatt_assigned_characteristics.txt @ b2b66ec139495c2b0b242d22d973dac87d75463c
// - https://github.com/WebBluetoothCG/registries/blob/master/gatt_assigned_descriptors.txt     @ b2b66ec139495c2b0b242d22d973dac87d75463c

package com.juul.kable

import kotlin.uuid.Uuid

/** Known services. */
private val BluetoothServices by lazy {
    mapOf(
        "alert_notification" to 0x1811,
        "automation_io" to 0x1815,
        "battery_service" to 0x180F,
        "blood_pressure" to 0x1810,
        "body_composition" to 0x181B,
        "bond_management" to 0x181E,
        "continuous_glucose_monitoring" to 0x181F,
        "current_time" to 0x1805,
        "cycling_power" to 0x1818,
        "cycling_speed_and_cadence" to 0x1816,
        "device_information" to 0x180A,
        "environmental_sensing" to 0x181A,
        "fitness_machine" to 0x1826,
        "generic_access" to 0x1800,
        "generic_attribute" to 0x1801,
        "glucose" to 0x1808,
        "health_thermometer" to 0x1809,
        "heart_rate" to 0x180D,
        "http_proxy" to 0x1823,
        "human_interface_device" to 0x1812,
        "immediate_alert" to 0x1802,
        "indoor_positioning" to 0x1821,
        "internet_protocol_support" to 0x1820,
        "link_loss" to 0x1803,
        "location_and_navigation" to 0x1819,
        "mesh_provisioning" to 0x1827,
        "mesh_proxy" to 0x1828,
        "next_dst_change" to 0x1807,
        "object_transfer" to 0x1825,
        "phone_alert_status" to 0x180E,
        "pulse_oximeter" to 0x1822,
        "reconnection_configuration" to 0x1829,
        "reference_time_update" to 0x1806,
        "running_speed_and_cadence" to 0x1814,
        "scan_parameters" to 0x1813,
        "transport_discovery" to 0x1824,
        "tx_power" to 0x1804,
        "user_data" to 0x181C,
        "weight_scale" to 0x181D,
    )
}

/** Known characteristics. */
private val BluetoothCharacteristics by lazy {
    mapOf(
        "aerobic_heart_rate_lower_limit" to 0x2A7E,
        "aerobic_heart_rate_upper_limit" to 0x2A84,
        "aerobic_threshold" to 0x2A7F,
        "age" to 0x2A80,
        "aggregate" to 0x2A5A,
        "alert_category_id" to 0x2A43,
        "alert_category_id_bit_mask" to 0x2A42,
        "alert_level" to 0x2A06,
        "alert_notification_control_point" to 0x2A44,
        "alert_status" to 0x2A3F,
        "altitude" to 0x2AB3,
        "anaerobic_heart_rate_lower_limit" to 0x2A81,
        "anaerobic_heart_rate_upper_limit" to 0x2A82,
        "anaerobic_threshold" to 0x2A83,
        "analog" to 0x2A58,
        "analog_output" to 0x2A59,
        "apparent_wind_direction" to 0x2A73,
        "apparent_wind_speed" to 0x2A72,
        "barometric_pressure_trend" to 0x2AA3,
        "battery_level" to 0x2A19,
        "battery_level_state" to 0x2A1B,
        "battery_power_state" to 0x2A1A,
        "blood_pressure_feature" to 0x2A49,
        "blood_pressure_measurement" to 0x2A35,
        "body_composition_feature" to 0x2A9B,
        "body_composition_measurement" to 0x2A9C,
        "body_sensor_location" to 0x2A38,
        "bond_management_control_point" to 0x2AA4,
        "bond_management_feature" to 0x2AA5,
        "boot_keyboard_input_report" to 0x2A22,
        "boot_keyboard_output_report" to 0x2A32,
        "boot_mouse_input_report" to 0x2A33,
        "cgm_feature" to 0x2AA8,
        "cgm_measurement" to 0x2AA7,
        "cgm_session_run_time" to 0x2AAB,
        "cgm_session_start_time" to 0x2AAA,
        "cgm_specific_ops_control_point" to 0x2AAC,
        "cgm_status" to 0x2AA9,
        "cross_trainer_data" to 0x2ACE,
        "csc_feature" to 0x2A5C,
        "csc_measurement" to 0x2A5B,
        "current_time" to 0x2A2B,
        "cycling_power_control_point" to 0x2A66,
        "cycling_power_feature" to 0x2A65,
        "cycling_power_measurement" to 0x2A63,
        "cycling_power_vector" to 0x2A64,
        "database_change_increment" to 0x2A99,
        "date_of_birth" to 0x2A85,
        "date_of_threshold_assessment" to 0x2A86,
        "date_time" to 0x2A08,
        "date_utc" to 0x2AED,
        "day_date_time" to 0x2A0A,
        "day_of_week" to 0x2A09,
        "descriptor_value_changed" to 0x2A7D,
        "dew_point" to 0x2A7B,
        "digital" to 0x2A56,
        "digital_output" to 0x2A57,
        "dst_offset" to 0x2A0D,
        "elevation" to 0x2A6C,
        "email_address" to 0x2A87,
        "exact_time_100" to 0x2A0B,
        "exact_time_256" to 0x2A0C,
        "fat_burn_heart_rate_lower_limit" to 0x2A88,
        "fat_burn_heart_rate_upper_limit" to 0x2A89,
        "firmware_revision_string" to 0x2A26,
        "first_name" to 0x2A8A,
        "fitness_machine_control_point" to 0x2AD9,
        "fitness_machine_feature" to 0x2ACC,
        "fitness_machine_status" to 0x2ADA,
        "five_zone_heart_rate_limits" to 0x2A8B,
        "floor_number" to 0x2AB2,
        "gap.appearance" to 0x2A01,
        "gap.central_address_resolution_support" to 0x2AA6,
        "gap.device_name" to 0x2A00,
        "gap.peripheral_preferred_connection_parameters" to 0x2A04,
        "gap.peripheral_privacy_flag" to 0x2A02,
        "gap.reconnection_address" to 0x2A03,
        "gatt.service_changed" to 0x2A05,
        "gender" to 0x2A8C,
        "glucose_feature" to 0x2A51,
        "glucose_measurement" to 0x2A18,
        "glucose_measurement_context" to 0x2A34,
        "gust_factor" to 0x2A74,
        "hardware_revision_string" to 0x2A27,
        "heart_rate_control_point" to 0x2A39,
        "heart_rate_max" to 0x2A8D,
        "heart_rate_measurement" to 0x2A37,
        "heat_index" to 0x2A7A,
        "height" to 0x2A8E,
        "hid_control_point" to 0x2A4C,
        "hid_information" to 0x2A4A,
        "hip_circumference" to 0x2A8F,
        "http_control_point" to 0x2ABA,
        "http_entity_body" to 0x2AB9,
        "http_headers" to 0x2AB7,
        "http_status_code" to 0x2AB8,
        "https_security" to 0x2ABB,
        "humidity" to 0x2A6F,
        "ieee_11073-20601_regulatory_certification_data_list" to 0x2A2A,
        "indoor_bike_data" to 0x2AD2,
        "indoor_positioning_configuration" to 0x2AAD,
        "intermediate_blood_pressure" to 0x2A36,
        "intermediate_cuff_pressure" to 0x2A36,
        "intermediate_temperature" to 0x2A1E,
        "irradiance" to 0x2A77,
        "language" to 0x2AA2,
        "last_name" to 0x2A90,
        "latitude" to 0x2AAE,
        "ln_control_point" to 0x2A6B,
        "ln_feature" to 0x2A6A,
        "local_east_coordinate.xml" to 0x2AB1,
        "local_north_coordinate" to 0x2AB0,
        "local_time_information" to 0x2A0F,
        "location_and_speed" to 0x2A67,
        "location_name" to 0x2AB5,
        "longitude" to 0x2AAF,
        "magnetic_declination" to 0x2A2C,
        "magnetic_flux_density_2D" to 0x2AA0,
        "magnetic_flux_density_3D" to 0x2AA1,
        "manufacturer_name_string" to 0x2A29,
        "maximum_recommended_heart_rate" to 0x2A91,
        "measurement_interval" to 0x2A21,
        "model_number_string" to 0x2A24,
        "navigation" to 0x2A68,
        "network_availability" to 0x2A3E,
        "new_alert" to 0x2A46,
        "object_action_control_point" to 0x2AC5,
        "object_changed" to 0x2AC8,
        "object_first_created" to 0x2AC1,
        "object_id" to 0x2AC3,
        "object_last_modified" to 0x2AC2,
        "object_list_control_point" to 0x2AC6,
        "object_list_filter" to 0x2AC7,
        "object_name" to 0x2ABE,
        "object_properties" to 0x2AC4,
        "object_size" to 0x2AC0,
        "object_type" to 0x2ABF,
        "ots_feature" to 0x2ABD,
        "plx_continuous_measurement" to 0x2A5F,
        "plx_features" to 0x2A60,
        "plx_spot_check_measurement" to 0x2A5E,
        "pnp_id" to 0x2A50,
        "pollen_concentration" to 0x2A75,
        "position_2d" to 0x2A2F,
        "position_3d" to 0x2A30,
        "position_quality" to 0x2A69,
        "pressure" to 0x2A6D,
        "protocol_mode" to 0x2A4E,
        "pulse_oximetry_control_point" to 0x2A62,
        "rainfall" to 0x2A78,
        "record_access_control_point" to 0x2A52,
        "reference_time_information" to 0x2A14,
        "removable" to 0x2A3A,
        "report" to 0x2A4D,
        "report_map" to 0x2A4B,
        "resolvable_private_address_only" to 0x2AC9,
        "resting_heart_rate" to 0x2A92,
        "ringer_control_point" to 0x2A40,
        "ringer_setting" to 0x2A41,
        "rower_data" to 0x2AD1,
        "rsc_feature" to 0x2A54,
        "rsc_measurement" to 0x2A53,
        "sc_control_point" to 0x2A55,
        "scan_interval_window" to 0x2A4F,
        "scan_refresh" to 0x2A31,
        "scientific_temperature_celsius" to 0x2A3C,
        "secondary_time_zone" to 0x2A10,
        "sensor_location" to 0x2A5D,
        "serial_number_string" to 0x2A25,
        "service_required" to 0x2A3B,
        "software_revision_string" to 0x2A28,
        "sport_type_for_aerobic_and_anaerobic_thresholds" to 0x2A93,
        "stair_climber_data" to 0x2AD0,
        "step_climber_data" to 0x2ACF,
        "string" to 0x2A3D,
        "supported_heart_rate_range" to 0x2AD7,
        "supported_inclination_range" to 0x2AD5,
        "supported_new_alert_category" to 0x2A47,
        "supported_power_range" to 0x2AD8,
        "supported_resistance_level_range" to 0x2AD6,
        "supported_speed_range" to 0x2AD4,
        "supported_unread_alert_category" to 0x2A48,
        "system_id" to 0x2A23,
        "tds_control_point" to 0x2ABC,
        "temperature" to 0x2A6E,
        "temperature_celsius" to 0x2A1F,
        "temperature_fahrenheit" to 0x2A20,
        "temperature_measurement" to 0x2A1C,
        "temperature_type" to 0x2A1D,
        "three_zone_heart_rate_limits" to 0x2A94,
        "time_accuracy" to 0x2A12,
        "time_broadcast" to 0x2A15,
        "time_source" to 0x2A13,
        "time_update_control_point" to 0x2A16,
        "time_update_state" to 0x2A17,
        "time_with_dst" to 0x2A11,
        "time_zone" to 0x2A0E,
        "training_status" to 0x2AD3,
        "treadmill_data" to 0x2ACD,
        "true_wind_direction" to 0x2A71,
        "true_wind_speed" to 0x2A70,
        "two_zone_heart_rate_limit" to 0x2A95,
        "tx_power_level" to 0x2A07,
        "uncertainty" to 0x2AB4,
        "unread_alert_status" to 0x2A45,
        "uri" to 0x2AB6,
        "user_control_point" to 0x2A9F,
        "user_index" to 0x2A9A,
        "uv_index" to 0x2A76,
        "vo2_max" to 0x2A96,
        "waist_circumference" to 0x2A97,
        "weight" to 0x2A98,
        "weight_measurement" to 0x2A9D,
        "weight_scale_feature" to 0x2A9E,
        "wind_chill" to 0x2A79,
    )
}

/** Known descriptors. */
private val BluetoothDescriptors by lazy {
    mapOf(
        "es_configuration" to 0x290B,
        "es_measurement" to 0x290C,
        "es_trigger_setting" to 0x290D,
        "external_report_reference" to 0x2907,
        "gatt.characteristic_aggregate_format" to 0x2905,
        "gatt.characteristic_extended_properties" to 0x2900,
        "gatt.characteristic_presentation_format" to 0x2904,
        "gatt.characteristic_user_description" to 0x2901,
        "gatt.client_characteristic_configuration" to 0x2902,
        "gatt.server_characteristic_configuration" to 0x2903,
        "number_of_digitals" to 0x2909,
        "report_reference" to 0x2908,
        "time_trigger_setting" to 0x290E,
        "valid_range" to 0x2906,
        "value_trigger_setting" to 0x290A,
    )
}

/** Gets a service [Uuid] from a known service [name]. */
@ExperimentalApi
public fun Uuid.Companion.service(name: String): Uuid =
    BluetoothServices[name]
        ?.let { Bluetooth.BaseUuid + it }
        ?: throw NoSuchElementException("Unknown Bluetooth service name: $name")

/** Gets a characteristic [Uuid] from a known characteristic [name]. */
@ExperimentalApi
public fun Uuid.Companion.characteristic(name: String): Uuid =
    BluetoothCharacteristics[name]
        ?.let { Bluetooth.BaseUuid + it }
        ?: throw NoSuchElementException("Unknown Bluetooth characteristic name: $name")

/** Gets a descriptor [Uuid] from a known descriptor [name]. */
@ExperimentalApi
public fun Uuid.Companion.descriptor(name: String): Uuid =
    BluetoothDescriptors[name]
        ?.let { Bluetooth.BaseUuid + it }
        ?: throw NoSuchElementException("Unknown Bluetooth descriptor name: $name")
